
#ifndef __DB_H__
#define __DB_H__
#include "util.hpp"
#include <mutex>
#include <cassert>

class user_table
{
public:
   user_table(const std::string &host,
              const std::string &username,
              const std::string &password,
              const std::string &dbname,
              uint16_t port = 3306) // 初始化
   {
      mysql = mysql_util::mysql_create(host, username, password, dbname, port);
      assert(mysql != NULL);
   }
   ~user_table()
   {
      mysql_util::mysql_destroy(mysql);
      mysql = NULL;
   } // 析构

   bool insert(Json::Value &user)
   {
#define INSERT_USER "insert user values(null, '%s', '%s', 1000, 0, 0)"

      if (user["password"].isNull() || user["username"].isNull())
      {
         DBG_LOG("INPUT PASSWORD OR USERNAME"); 
         return false;
      }

      char buffer[4096] = {0};
      // 记得user["username"]要有.asCString()-----转换成char*
      sprintf(buffer, INSERT_USER, user["username"].asCString(), user["password"].asCString()); // 别忘了要变成char*
      bool ret = mysql_util::mysql_exec(mysql, buffer);
      if (ret == false)
      {
         DBG_LOG("insert user info failed!!\n");
         return false;
      }
      return true;
   } // 插入用户数据

   bool login(Json::Value &user) // 登录请求------即外部只给出密码和username，其他的如id，score这些都是需要我们获取后再填充user的！！！！！
   {
      if (user["password"].isNull() || user["username"].isNull())
      {
         DBG_LOG("INPUT PASSWORD OR USERNAME");
         return false;  
      }
#define USER_LOGIN_ "select id,score,total_count,win_count from user where username = '%s' and password = '%s'"
      char buffer[4096] = {0};
      // 记得user["username"]要有.asCString()-----转换成char*
      sprintf(buffer, USER_LOGIN_, user["username"].asCString(), user["password"].asCString()); // 别忘了要变成char*

      // 这里设置一个作用域，并添加一个互斥锁，保证执行sql语句和获取结果至本地要同步完成，结束作用域后锁自动销毁：：std::unique_lock<std::mutex> lock(_mutex);
      MYSQL_RES *res = NULL;
      {
         std::unique_lock<std::mutex> lock(_mutex);
         bool ret = mysql_util::mysql_exec(mysql, buffer);
         if (ret == false)
         {
            DBG_LOG("insert user info failed!!\n");
            return false;
         }

         res = mysql_store_result(mysql); // 查询结果获取到本地
         if (res == NULL)
         {
            DBG_LOG("have no user info!!");
            return false;
         }
      }

      // 如果存在多个有同一个name的数据，说明出错！！！！！-------即row_num要么只有一个，要么就没有，多个说明有误！！！
      int row_num = mysql_num_rows(res);
      if (row_num != 1)
      {
         DBG_LOG("the user information queried is not unique!!");
         return false;
      }



      // 获取那一行的数据并填写入root之中！！！！！！
      MYSQL_ROW row = mysql_fetch_row(res); // mysql_fetch_rows函数----------从查询结果集中获取一行数据，返回一个字符串数组（MYSQL_ROW 类型），数组的每个元素对应一个字段的值（以 char* 形式存储）。
      user["id"] = (Json::UInt64)std::stol(row[0]);
      user["score"] = (Json::UInt64)std::stol(row[1]);
      user["total_count"] = (Json::UInt64)std::stol(row[2]);
      user["win_count"] = (Json::UInt64)std::stol(row[3]);
      mysql_free_result(res); // 别忘了要清除res
      return true;
   }

   bool select_byname(Json::Value &root, const std::string &name)
   {
      // 注意这里最后使用的是'%s'  不是双引号，记住了！！！！！！！！！！
      // 设置sql查询语句
#define USER_BY_NAME "select id,score,total_count,win_count from user where username = '%s'"
      char buffer[4096] = {0};
      sprintf(buffer, USER_BY_NAME, name.c_str()); // 别忘了要变成char*

     MYSQL_RES *res = NULL;
      {
         std::unique_lock<std::mutex> lock(_mutex);
         bool ret = mysql_util::mysql_exec(mysql, buffer);
         if (ret == false)
         {
            DBG_LOG("insert user info failed!!\n");
            return false;
         }

         res = mysql_store_result(mysql); // 查询结果获取到本地
         if (res == NULL)
         {
            DBG_LOG("have no user info!!");
            return false;
         }
      }

      // 如果存在多个有同一个name的数据，说明出错！！！！！-------即row_num要么只有一个，要么就没有，多个说明有误！！！
      int row_num = mysql_num_rows(res);
      if (row_num != 1)
      {
         DBG_LOG("the user information queried is not unique!!");
         return false;
      }

      // 获取那一行的数据并填写入root之中！！！！！！
      MYSQL_ROW row = mysql_fetch_row(res); // mysql_fetch_rows函数----------从查询结果集中获取一行数据，返回一个字符串数组（MYSQL_ROW 类型），数组的每个元素对应一个字段的值（以 char* 形式存储）。
      root["id"] = (Json::UInt64)std::stol(row[0]);
      root["username"] = name;
      root["score"] = (Json::UInt64)std::stol(row[1]);
      root["total_count"] = (Json::UInt64)std::stol(row[2]); // 记得要转换为整型，然后再转换为json中的UInt64类型！！！
      root["win_count"] = (Json::UInt64)std::stol(row[3]);
      mysql_free_result(res); // 别忘了要清除res
      return true;

   } // 按用户名搜索,并把对应的数据放入root中

   bool select_id(Json::Value &root, uint64_t id)
   {
      // 注意这里最后使用的是%d  不要有引号，记住了！！！！！！！！！！-------
      // 设置sql查询语句
#define USER_BY_ID "select username,score,total_count,win_count from user where id = %ld"
      char buffer[4096] = {0};
      sprintf(buffer, USER_BY_ID, id);       // 别忘了要变成char*
      
      MYSQL_RES *res = NULL;
      {
         std::unique_lock<std::mutex> lock(_mutex);
         bool ret = mysql_util::mysql_exec(mysql, buffer);
         if (ret == false)
         {
            DBG_LOG("insert user info failed!!\n");
            return false;
         }

         res = mysql_store_result(mysql); // 查询结果获取到本地
         if (res == NULL)
         {
            DBG_LOG("have no user info!!");
            return false;
         }
      }

      // 如果存在多个有同一个id的数据，说明出错！！！！！-------即row_num要么只有一个，要么就没有，多个说明有误！！！
      int row_num = mysql_num_rows(res);
      if (row_num != 1)
      {
         DBG_LOG("the user information queried is not unique!!");
         return false;
      }

      // 获取那一行的数据并填写入root之中！！！！！！
      MYSQL_ROW row = mysql_fetch_row(res); // mysql_fetch_rows函数----------从查询结果集中获取一行数据，返回一个字符串数组（MYSQL_ROW 类型），数组的每个元素对应一个字段的值（以 char* 形式存储）。
      root["id"] = (Json::UInt64)id;
      root["username"] = row[0];
      root["score"] = (Json::UInt64)std::stol(row[1]);
      root["total_count"] = (Json::UInt64)std::stol(row[2]);
      root["win_count"] = (Json::UInt64)std::stol(row[3]);
      mysql_free_result(res); // 别忘了要清除res 
      return true;
   } // 按id搜索

   bool win(uint64_t id)
   {
#define WIN_USER "update user set score=score+30,total_count=total_count+1,win_count=win_count+1 where id = %ld"
      char buffer[4096] = {0};
      // 记得user["username"]要有.asCString()-----转换成char*
      sprintf(buffer, WIN_USER, id); // 别忘了要变成char*
      bool ret = mysql_util::mysql_exec(mysql, buffer);
      if (ret == false)
      {
         DBG_LOG("insert user info failed!!\n");
         return false;
      }
      return true;
   } // 胜利，分数上升，场数增加，胜利场数增加

   bool lose(uint64_t id)
   {
#define USER_LOSE "update user set score=score-30, total_count=total_count+1 where id= %ld;"
      char buffer[4096] = {0};
      sprintf(buffer, USER_LOSE, id);
      bool ret = mysql_util::mysql_exec(mysql, buffer);
      if (ret == false)
      {
         DBG_LOG("update lose user info failed!!\n");
         return false;
      }
      return true;
   } // 失败，分数下降，场数增加，胜利场数不变

private:
   MYSQL *mysql; 
   std::mutex _mutex;
};

#endif